#include "log.h"
#include "sdl2/SDL_egl.h"
#include "SDL2/SDL_syswm.h"
#include <EGL/egl.h>
#include <GLES3/gl3.h>
SDL_Window* g_win;
int g_winw;
int g_winh;

EGLContext g_context;
EGLDisplay g_display;
EGLSurface g_surface;
void* GetEGLContext()
{
	return g_context;
}
int Init_Angle_EGL(SDL_Window* win);

static GLuint loadShader(GLenum type, const char* source);
void GL_Init(SDL_Window* win)
{
	g_win = win;

	SDL_GetWindowSize(g_win, &g_winw, &g_winh);
	Init_Angle_EGL(win);
	//Init_NoWindow_EGL();


	const char* vs1 = 
"#version 300 es\n\
	precision mediump float;\n\
	layout(location = 0) in vec4 a_position;\n\
	layout(location = 1) in vec2 a_textureCoordinate;\n\
	out vec2 v_textureCoordinate;\n\
	void main() {\n\
		v_textureCoordinate = a_textureCoordinate;\n\
		gl_Position = a_position;\n\
	}\n\
";

	GLuint handle = loadShader(GL_VERTEX_SHADER, vs1);

}
void GL_Resize(int w, int h)
{
	g_winw = w;
	g_winh = h;
}
void GL_ViewPort()
{
	glViewport(0, 0, g_winw, g_winh);

}
void GL_Flush()
{
	eglSwapBuffers(g_display, g_surface);
}
void GL_Loop()
{

	glClearColor(1.0f, 0.5f, 0.5f, 0.0f);
	glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

	// camera for glfw window

	//float view[16], projection[16];
	//fpsCameraViewMatrix(view);
	//perspectiveMatrix(projection, 45.0f, (float)g_winw / (float)g_winh, 0.01f, 100.0f);

	//drawScene(&scene, view, projection);


}



int Init_Angle_EGL(SDL_Window* win)
{
	EGLint configAttribList[] =
	{
		EGL_RED_SIZE, 8,
		EGL_GREEN_SIZE, 8,
		EGL_BLUE_SIZE, 8,
		EGL_ALPHA_SIZE, 8,
		EGL_DEPTH_SIZE, 8,
		EGL_STENCIL_SIZE, 8,
		EGL_SAMPLE_BUFFERS, 1,
		EGL_NONE };
	EGLint surfaceAttribList[] =
	{
		EGL_POST_SUB_BUFFER_SUPPORTED_NV, EGL_FALSE,
		EGL_NONE, EGL_NONE };

	EGLint numConfigs;
	EGLint majorVersion;
	EGLint minorVersion;
	EGLDisplay display;
	EGLSurface surface;
	EGLConfig config;
	EGLint contextAttribs[] = { EGL_CONTEXT_CLIENT_VERSION, 2, EGL_NONE, EGL_NONE };

	SDL_SysWMinfo info;
	SDL_VERSION(&info.version); // initialize info structure with SDL version info
	SDL_bool get_win_info = SDL_GetWindowWMInfo(win, &info);
	//SDL_assert_release(get_win_info);
	EGLNativeWindowType hWnd = info.info.win.window;

	// Get Display
	void* hdc = GetDC(hWnd);
	display = eglGetDisplay((EGLNativeDisplayType)hdc); // EGL_DEFAULT_DISPLAY
	if (display == EGL_NO_DISPLAY)
	{
		return EGL_FALSE;
	}

	// Initialize EGL
	if (!eglInitialize(display, &majorVersion, &minorVersion))
	{
		return EGL_FALSE;
	}

	// Get configs
	if (!eglGetConfigs(display, NULL, 0, &numConfigs))
	{
		return EGL_FALSE;
	}

	// Choose config
	if (!eglChooseConfig(display, configAttribList, &config, 1, &numConfigs))
	{
		return EGL_FALSE;
	}

	// Create a surface
	surface = eglCreateWindowSurface(display, config, (EGLNativeWindowType)hWnd, surfaceAttribList);
	if (surface == EGL_NO_SURFACE)
	{
		return EGL_FALSE;
	}

	// Create a GL context
	g_context = eglCreateContext(display, config, EGL_NO_CONTEXT, contextAttribs);
	if (g_context == EGL_NO_CONTEXT)
	{
		return EGL_FALSE;
	}

	// Make the context current
	if (!eglMakeCurrent(display, surface, surface, g_context))
	{
		return EGL_FALSE;
	}
	const char* rd = (const char*)glGetString(GL_RENDERER);
	const char* verstr = (const char*)glGetString(GL_VERSION);
	const char* shaderstr = (const char*)glGetString(GL_SHADING_LANGUAGE_VERSION);
	printlogf ("GL_RENDERER: %s\n", rd);
	printlogf("GL_VERSION: %s\n", verstr);
	printlogf("GL_SHADING_LANGUAGE_VERSION: %s\n", shaderstr);
	//swap->display = display;
	//swap->surface = surface;

	g_display = display;
	g_surface = surface;
	return EGL_TRUE;
}



static GLuint loadShader(GLenum type, const char* source)
{
	GLuint shader = glCreateShader(type);
	if (shader == 0)
	{
		printlogf("Could not create shader!\n");
		return 0;
	}
	glShaderSource(shader, 1, &source, NULL);
	glCompileShader(shader);
	GLint compiled;
	glGetShaderiv(shader, GL_COMPILE_STATUS, &compiled);
	if (!compiled)
	{
		printlogf("Could not compile shader!\n");
		GLint infoLen = 0;
		glGetShaderiv(shader, GL_INFO_LOG_LENGTH, &infoLen);
		if (infoLen)
		{
			char* infoLog = (char*)malloc(infoLen);
			glGetShaderInfoLog(shader, infoLen, NULL, infoLog);
			printlogf("%s\n", infoLog);
			free(infoLog);
		}
		glDeleteShader(shader);
		return 0;
	}
	return shader;
}
static GLuint loadProgram(const char* vp, const char* fp, const char** attributes, int attributeCount)
{
	GLuint vertexShader = loadShader(GL_VERTEX_SHADER, vp);
	if (!vertexShader)
		return 0;
	GLuint fragmentShader = loadShader(GL_FRAGMENT_SHADER, fp);
	if (!fragmentShader)
	{
		glDeleteShader(vertexShader);
		return 0;
	}

	GLuint program = glCreateProgram();
	if (program == 0)
	{
		printlogf( "Could not create program!\n");
		return 0;
	}
	glAttachShader(program, vertexShader);
	glAttachShader(program, fragmentShader);

	for (int i = 0; i < attributeCount; i++)
		glBindAttribLocation(program, i, attributes[i]);

	glLinkProgram(program);
	glDeleteShader(vertexShader);
	glDeleteShader(fragmentShader);
	GLint linked;
	glGetProgramiv(program, GL_LINK_STATUS, &linked);
	if (!linked)
	{
		printlogf("Could not link program!\n");
		GLint infoLen = 0;
		glGetProgramiv(program, GL_INFO_LOG_LENGTH, &infoLen);
		if (infoLen)
		{
			char* infoLog = (char*)malloc(sizeof(char) * infoLen);
			glGetProgramInfoLog(program, infoLen, NULL, infoLog);
			printlogf( "%s\n", infoLog);
			free(infoLog);
		}
		glDeleteProgram(program);
		return 0;
	}
	return program;
}
